home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / networking / streamnop / streamnop.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  12.7 KB  |  426 lines

  1. /*
  2.     File:        StreamNOP.c
  3.  
  4.     Contains:    Stream module that does nothing.
  5.  
  6.     Written by: Quinn "The Eskimo!"    
  7.  
  8.     Copyright:    Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/23/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23. /////////////////////////////////////////////////////////////////////
  24. // The OT debugging macros in <OTDebug.h> require this variable to
  25. // be set.
  26.  
  27. #ifndef qDebug
  28. #define qDebug    1
  29. #endif
  30.  
  31. /////////////////////////////////////////////////////////////////////
  32. // Determine whether this is going to be an instrumented build or not.
  33.  
  34. #ifndef INSTRUMENTATION_ACTIVE
  35.     #define INSTRUMENTATION_ACTIVE 0
  36. #else
  37.     #define INSTRUMENTATION_ACTIVE 1
  38. #endif
  39.  
  40. /////////////////////////////////////////////////////////////////////
  41. // Pick up all the standard OT module stuff.
  42.  
  43. #include <OpenTptModule.h>
  44.  
  45. /////////////////////////////////////////////////////////////////////
  46. // Pick up the OTDebugBreak and OTAssert macros.
  47.  
  48. #include <OTDebug.h>
  49.  
  50. /////////////////////////////////////////////////////////////////////
  51. // Pick up all the standard TPI/DLPI constants and structures.
  52.  
  53. #include <tihdr.h>
  54. #include <dlpi.h>
  55.  
  56. /////////////////////////////////////////////////////////////////////
  57. // Pick up Instrumentation SDK stuff.  We only do this if we're
  58. // actually instrumenting, so you don't even have to have the SDK
  59. // to compile the non-instumented version of the code.  If we're
  60. // not instrumenting, we compile a bunch of bogus macros that generally
  61. // compile to nothing.
  62.  
  63. #if INSTRUMENTATION_ACTIVE
  64.     #include <InstrumentationMacros.h>
  65. #else
  66.     #define TRACE_SETUP        long __junk
  67.     #define LOG_ENTRY(n)    if (0) { __junk ; }
  68.     #define LOG_EXIT        if (0) { __junk ; }
  69. #endif
  70.  
  71. /////////////////////////////////////////////////////////////////////
  72. // OTDebugStr is not defined in any OT header files, but it is
  73. // exported by the libraries, so we define the prototype here.
  74.  
  75. extern pascal void OTDebugStr(const char* str);
  76.  
  77. /////////////////////////////////////////////////////////////////////
  78. // Some simple routines we use in our various assertions.
  79.  
  80. static Boolean IsReadQ(queue_t* q)
  81.     // Returns true if q is the read queue of a queue pair.
  82. {
  83.     return ( (q->q_flag & QREADR) != 0 );
  84. }
  85.  
  86. static Boolean IsWriteQ(queue_t* q)
  87.     // Returns true if q is the write queue of a queue pair.
  88. {
  89.     return ( (q->q_flag & QREADR) == 0 );
  90. }
  91.  
  92. /////////////////////////////////////////////////////////////////////
  93. // Per-Stream information
  94.  
  95. // This structure is used to hold the per-stream data for the module.
  96. // While module's can use normal global variables to store real globals,
  97. // they must maintain their own per-stream data structures.  I use
  98. // mi_open_comm to allocate this data structure when the stream is
  99. // opened.  mi_open_comm stores the address of this data structure in the
  100. // read and write queue's q_ptr field, so the rest of the code
  101. // can get to it by calling the GetPerStreamData function.
  102.  
  103. enum {
  104.     kStreamNOPPerStreamDataMagic = 'NOOP'
  105. };
  106.  
  107. struct PerStreamData
  108. {
  109.     OSType                 magic;                // kStreamNOPPerStreamDataMagic = 'NOOP' for debugging
  110.     // Your per-stream data structures go here.
  111. };
  112. typedef struct PerStreamData PerStreamData, *PerStreamDataPtr;
  113.  
  114. static PerStreamDataPtr GetPerStreamData(queue_t* readOrWriteQ)
  115.     // You can pass both the read or the write queue to this routine
  116.     // because mi_open_comm sets up both q_ptr's to point to the
  117.     // queue local data.
  118.     //
  119.     // Note that, in order to avoid the overhead of a function call,
  120.     // you would normally use inline code (or a macro)
  121.     // to get your per-stream data instead of using a separate function.
  122.     // However I think the separate function makes things clearer.
  123.     // I also acts as a central bottleneck for my debugging code.
  124.     //
  125.     // Environment: any standard STREAMS entry point
  126. {
  127.     PerStreamDataPtr streamData;
  128.     
  129.     streamData = (PerStreamDataPtr) readOrWriteQ->q_ptr;
  130.  
  131.     OTAssert("GetPerStreamData: what streamData", streamData != nil);
  132.     OTAssert("GetPerStreamData: Bad magic", streamData->magic == kStreamNOPPerStreamDataMagic);
  133.     
  134.     return (streamData);
  135. }
  136.  
  137. // mi_open_comm and mi_close_comm (and also mi_detach and mi_close_detached)
  138. // use this global to store the list of open streams to this module.
  139.  
  140. static char* gStreamList = nil;
  141.  
  142. /////////////////////////////////////////////////////////////////////
  143. // Open routine
  144.  
  145. static int StreamNOPOpen(queue_t* rdq, dev_t* dev, int flag, int sflag, cred_t* creds)
  146.     // This routine is called by STREAMS when a new stream is connected to
  147.     // our module.  The bulk of the work here is done by the Mentat helper
  148.     // routine mi_open_comm.
  149.     //
  150.     // Environment: standard STREAMS entry point
  151. {
  152.     TRACE_SETUP;
  153.     int err;
  154.     PerStreamDataPtr streamData;
  155.  
  156.     LOG_ENTRY( "StreamNOP:StreamNOPOpen" );
  157.     
  158.     OTAssert("StreamNOPOpen: Not the read queue", IsReadQ(rdq) );
  159.  
  160.     OTDebugBreak("StreamNOPOpen");
  161.     
  162.     err = noErr;
  163.     
  164.     // If we already have per-stream data for this stream, the stream is being reopened.
  165.     // In that case, we can just return.
  166.     // Note that we can't call GetPerStreamData because it checks that streamData is not nil.
  167.     
  168.     if ( rdq->q_ptr != nil ) {
  169.         goto done;
  170.     }
  171.  
  172.     // Make sure we're being opened properly -- because we're a module we
  173.     // require a "module" open.  Other possibilities are the value 0 (used
  174.     // to open a specific minor device number (ie stream) on a device driver),
  175.     // and CLONEOPEN (used to open a new stream to a device number where you
  176.     // don't care what device number you get -- the typical behaviour for
  177.     // networking (as opposed to serial) devices).
  178.     
  179.     if ( (err == noErr) && (sflag != MODOPEN) ) {
  180.         err = ENXIO;
  181.     }
  182.     
  183.     // Use the mi_open_comm routine to allocate our per-stream data.  Then
  184.     // zero out the entire per-stream data record and fill out the fields
  185.     // we're going to need.
  186.     
  187.     if (err == noErr) {
  188.         err = mi_open_comm(&gStreamList, sizeof(PerStreamData), rdq, dev, flag, sflag, creds);
  189.         if ( err == noErr ) {
  190.             // Note that we can't call GetPerStreamData because the magic is not set up yet.
  191.             streamData = (PerStreamDataPtr) rdq->q_ptr;
  192.             
  193.             OTMemzero(streamData, sizeof(PerStreamData));
  194.             
  195.             streamData->magic = kStreamNOPPerStreamDataMagic;
  196.         }
  197.     }
  198.  
  199. done:
  200.     LOG_EXIT;
  201.     return (err);
  202. }
  203.  
  204. /////////////////////////////////////////////////////////////////////
  205. // Close routine
  206.  
  207. static int StreamNOPClose(queue_t* rdq, int flags, cred_t* credP)
  208.     // This routine is called by STREAMS when a stream is being
  209.     // disconnected from our module (ie closed).  The bulk of the work
  210.     // is done by the magic Mentat helper routine mi_close_comm.
  211.     //
  212.     // Environment: standard STREAMS entry point
  213. {
  214.     TRACE_SETUP;
  215.     #pragma unused(flags)
  216.     #pragma unused(credP)
  217.  
  218.     LOG_ENTRY( "StreamNOP:StreamNOPClose" );
  219.  
  220.     OTAssert("StreamNOPClose: Not the read queue", IsReadQ(rdq) );
  221.  
  222.     (void) mi_close_comm(&gStreamList, rdq);
  223.  
  224.     LOG_EXIT;
  225.     return (0);
  226. }
  227.  
  228. /////////////////////////////////////////////////////////////////////
  229.  
  230. enum {
  231.     kNoPrimitive = -1
  232. };
  233.  
  234. static long GetPrimitive(mblk_t* mp)
  235.     // GetPrimitive gets the TPI/DLPI primitive out of a message block.
  236.     // It returns kNoPrimitive if the message block is of the wrong
  237.     // type or there is no primitive.
  238.     //
  239.     // Environment: any standard STREAMS entry point
  240. {
  241.     if ((mp->b_datap->db_type == M_PROTO || mp->b_datap->db_type == M_PCPROTO) && MBLK_SIZE(mp) >= sizeof(long) ) {
  242.         return ( ( (union T_primitives*) mp->b_rptr)->type );
  243.     } else {
  244.         return ( kNoPrimitive );
  245.     }
  246. }
  247.  
  248. /////////////////////////////////////////////////////////////////////
  249. // Write-side put routine
  250.  
  251. static int StreamNOPWritePut(queue_t* q, mblk_t* mp)
  252.     // This routine is called by STREAMS when it has a message for our
  253.     // module from upstream.  Typically, this routine is a big case statement
  254.     // that dispatches to our various message handling routines.  However, the 
  255.     // function of this stream module is to pass through all messages unchanged,
  256.     // so the case statement is not very exciting.
  257.     //
  258.     // Environment: standard STREAMS entry point
  259. {
  260.     TRACE_SETUP;
  261.     PerStreamDataPtr streamData;
  262.     
  263.     LOG_ENTRY( "StreamNOP:StreamNOPWritePut" );
  264.  
  265.     OTAssert("StreamNOPWritePut: Not the write queue", IsWriteQ(q) );
  266.  
  267.     // OTDebugBreak("StreamNOPWritePut: Entered");
  268.     
  269.     streamData = GetPerStreamData(q);
  270.  
  271.     switch ( GetPrimitive(mp) ) {
  272.         default:
  273.             putnext(q, mp);
  274.             break;
  275.     }
  276.     
  277.     LOG_EXIT;
  278.     
  279.     return 0;
  280. }
  281.  
  282. /////////////////////////////////////////////////////////////////////
  283. // Read-side put routine
  284.  
  285. static int StreamNOPReadPut(queue_t* q, mblk_t* mp)
  286.     // This routine is called by STREAMS when it has a message for our
  287.     // module from downstream.  Typically, this routine is a big case statement
  288.     // that dispatches to our various message handling routines.  However, the 
  289.     // function of this stream module is to pass through all messages unchanged,
  290.     // so the case statement is not very exciting.
  291.     //
  292.     // Environment: standard STREAMS entry point
  293. {
  294.     TRACE_SETUP;
  295.     PerStreamDataPtr streamData;
  296.     
  297.     LOG_ENTRY( "StreamNOP:StreamNOPReadPut" );
  298.  
  299.     OTAssert("StreamNOPReadPut: Not the read queue", IsReadQ(q) );
  300.  
  301.     // OTDebugBreak("StreamNOPReadPut: Entered");
  302.     
  303.     streamData = GetPerStreamData(q);
  304.  
  305.     switch ( GetPrimitive(mp) ) {
  306.         default:
  307.             putnext(q, mp);
  308.             break;
  309.     }
  310.     
  311.     LOG_EXIT;
  312.     
  313.     return 0;
  314. }
  315.  
  316. /////////////////////////////////////////////////////////////////////
  317. // Static Declaration Structures
  318.  
  319. static struct module_info gModuleInfo =  
  320. {
  321.     9992,                        // Module Number, only useful for debugging
  322.     "StreamNOP",                // Name of module
  323.     0,                            // Minimum data size
  324.     INFPSZ,                        // Maximum data size
  325.     16384,                        // Hi water mark for queue
  326.     4096                        // Lo water mark for queue
  327. };
  328.  
  329. static struct qinit gReadInit = 
  330. {
  331.     StreamNOPReadPut,        // Put routine for "incoming" data
  332.     nil,                        // Service routine for "incoming" data
  333.     StreamNOPOpen,            // Our open routine
  334.     StreamNOPClose,         // Our close routine
  335.     nil,                        // No admin routine
  336.     &gModuleInfo                // Our module_info
  337. };
  338.  
  339. static struct qinit gWriteInit =
  340. {
  341.     StreamNOPWritePut,        // Put routine for client data
  342.     nil,                        // Service routine for client data
  343.     nil,                        // open  field only used in read-side structure
  344.     nil,                        // close field only used in read-side structure
  345.     nil,                        // admin field only used in read-side structure
  346.     &gModuleInfo                // Our module_info
  347. };
  348.  
  349. static struct streamtab theStreamTab = 
  350. {
  351.     &gReadInit,                    // Our read-side qinit structure
  352.     &gWriteInit,                // Our write-side qinit structure
  353.     0,                            // We are not a mux, so set this to nil
  354.     0                            // We are not a mux, so set this to nil
  355. };
  356.  
  357. /////////////////////////////////////////////////////////////////////
  358. // Macintosh-specific Static Structures
  359.  
  360. static struct install_info theInstallInfo =
  361. {
  362.     &theStreamTab,            // Stream Tab pointer
  363.     kOTModIsModule + kOTModUpperIsTPI + kOTModIsFilter,
  364.                             // Tell OT that we are a driver, not a module
  365.     SQLVL_MODULE,            // Synchronization level, module level for the moment
  366.     0,                        // Shared writer list buddy
  367.     0,                        // Open Transport use - always set to 0
  368.     0                        // Flag - always set to 0
  369. };
  370.  
  371. // Prototypes for the exported routines below.
  372.  
  373. extern Boolean InitStreamModule(void *portInfo);
  374. extern void TerminateStreamModule(void);
  375. extern install_info* GetOTInstallInfo();
  376.  
  377. #pragma export list GetOTInstallInfo, InitStreamModule, TerminateStreamModule
  378.  
  379. // Export entry point
  380.  
  381. extern Boolean InitStreamModule(void *portInfo)
  382.     // Initialises the module before the first stream is opened.
  383.     // Should return true if the module has started up correctly.
  384.     //
  385.     // Environment: Always called at SystemTask time.
  386. {    
  387.     TRACE_SETUP;
  388.     #pragma unused(portInfo)
  389.     Boolean result;
  390.     
  391.     OTDebugBreak("StreamNOP: InitStreamModule");
  392.     
  393.     LOG_ENTRY( "StreamNOP:InitStreamModule" );
  394.  
  395.     result = true;
  396.     
  397.     LOG_EXIT;
  398.     return (result);
  399. }
  400.  
  401. extern void TerminateStreamModule(void)
  402.     // Shuts down the module after the last stream has been
  403.     // closed.
  404.     //
  405.     // Environment: Always called at SystemTask time.
  406. {
  407.     TRACE_SETUP;
  408.     
  409.     LOG_ENTRY( "StreamNOP:TerminateStreamModule" );
  410.     
  411.     // It's an excellent idea to have the following in your code, just to make
  412.     // sure you haven't left any streams open before you quit.  In theory, OT
  413.     // should not call you until the last stream has been closed, but in practice
  414.     // this can happen if you use mi_detach to half-close a stream.
  415.     
  416.     OTAssert("TerminateStreamModule: Streams are still active", gStreamList == nil);
  417.  
  418.     LOG_EXIT;
  419. }
  420.  
  421. extern install_info* GetOTInstallInfo()
  422.     // Return pointer to install_info to STREAMS.
  423. {
  424.     return &theInstallInfo;
  425. }
  426.